package testApplets;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;

import meshToSolid.Selector;

import peasy.PeasyCam;
import processing.core.PApplet;
import simpleGeom.Bounds3D;
import simpleGeom.Face3D;
import simpleGeom.HasPos3D;
import simpleGeom.Node;
import simpleGeom.SimpleObjLoaderStream;
import simpleGeom.SimpleTriangle;
import simpleGeom.TrianglePreCalc;
import simpleGeom.Vec3D;


public class StitchApplet extends PApplet {
	String folderPath="/Users/caad/Desktop/Archive/";
	//String inputPath=folderPath+"grottoVolume.obj";
	String fileIn1=folderPath+"grotto1e20revisit4.obj30_20_65_28.obj";
	String fileOut=folderPath+"grotto1e20revisit4.obj30_20_65_28.obj";
	//String outputPath=folderPath+"grotto1e20revisit4.obj30_20_65_28Sel.obj";

	BorderNodes m1=new BorderNodes();
	BorderNodes m2=new BorderNodes();
	Vector<SimpleTriangle>cutFaces=new Vector<SimpleTriangle>();
	PeasyCam cam;
public void setup(){
	size(1600,900,P3D);
	
	m1.loadObj(folderPath+"grotto1e20revisit4.obj30_20_65_28Sel.obj");
	m1.deleteBackFaces(0.3f);
	m1.collectBorders();
	m2.loadObj(folderPath+"skinTestVersion1gRight21_17_80_18Sel.obj");
	m2.deleteBackFaces(0.2f);
	m2.collectBorders();
	m2.mirrorX();
	stitch();
	m2.invertFaces();
	m1.faces.addAll(m2.faces);
	m1.saveObjPrintwriter(folderPath+"tetsStitchBig.obj");
	
	//saveObjPrintwriter(folderPath+"tetsStitch.obj",stitches);
	cam=new PeasyCam(this,800);
}

public void draw(){
	background(0);
	noStroke();
	scale(300);
	m1.display();
	m2.display();
	stroke(0,255,0);
	fill(0,0,255);
	for (int i=0;i<stitches.size();i++){
		SimpleTriangle sT=stitches.get(i);
		sT.display3D(g);
	};
	fill(0,255,255);
	for (int i=0;i<cutFaces.size();i++){
		SimpleTriangle sT=cutFaces.get(i);
		sT.display3D(g);
	};
	
}
	Vector<SimpleTriangle>stitches=new Vector<SimpleTriangle>();
	public void stitch(Vector<Node>minNodes,Vector<Node>maxNodes){
		if (minNodes.size()>maxNodes.size()){
			Vector<Node>temp=minNodes;
			minNodes=maxNodes;
			maxNodes=temp;
		}
		for (int i=0;i<minNodes.size()-1;i++){
			Node nA=minNodes.get(i);
			Node nB=maxNodes.get(i);
			Node nC=maxNodes.get(i+1);
			Node nD=minNodes.get(i+1);
			SimpleTriangle t1=new SimpleTriangle(nA,nB,nC);
			m1.faces.add(t1);
			stitches.add(t1);
			SimpleTriangle t2=new SimpleTriangle(nA,nC,nD);
			m1.faces.add(t2);
			stitches.add(t2);
		}
		for (int i=minNodes.size()-1;i<maxNodes.size()-1;i++){
			Node nA=minNodes.lastElement();
			Node nB=maxNodes.get(i);
			Node nC=maxNodes.get(i+1);
			SimpleTriangle t1=new SimpleTriangle(nA,nB,nC);
			m1.faces.add(t1);
			stitches.add(t1);
		}
	}
	public void saveObjPrintwriter(String file,Vector<SimpleTriangle> faces) {
		PrintWriter output = createWriter(file + ".obj");

		int idV = 1;
		
		for (int i = 0; i < faces.size(); i++) {
			SimpleTriangle f = faces.get(i);
			for (int j = 0; j < f.getNodesNum(); j++) {
				Vec3D n = (Vec3D) f.getNode(j);
				
				if (n.getId() == 0) {
					n.setId(idV);
					idV++;
					output.println("v " + n.x + " " + n.y + " " + n.z);
				}
			}
		}
		
		
		for (int i = 0; i < faces.size(); i++) {
			SimpleTriangle f = faces.get(i);
			int[] ids = new int[f.getNodesNum()];
			String string = "f";
			
			for (int j = 0; j < f.getNodesNum(); j++) {
				Vec3D n = (Vec3D) f.getNode(j);
				string += " " + n.getId();
			}
			output.println(string);
		}
		
		output.flush(); // Writes the remaining data to the file
		output.close();
	}
public void stitch(){
	Collections.reverse(m1.nodesLeft);
	Collections.reverse(m2.nodesLeft);
		stitch(m1.nodesLeft,m2.nodesLeft);
	
	
	
		stitch(m1.nodesRight,m2.nodesRight);
	
	Collections.reverse(m1.nodesTop);
	Collections.reverse(m2.nodesTop);
		stitch(m1.nodesTop,m2.nodesTop);
		
		stitch(m1.nodesBottom,m2.nodesBottom);
}
class NodeComparator implements Comparator{
	int  axis;
	NodeComparator(int c){
		this.axis=c;
	}
	@Override
	public int compare(Object arg0, Object arg1) {
		Node n1=(Node) arg0;
		Node n2=(Node) arg1;
		if (axis==0){
			return Float.compare(n1.x, n2.x);
		}
		else if (axis==1){
			return Float.compare(n1.y, n2.y);
		}
		else if (axis==2){
			return Float.compare(n1.z, n2.z);
		}
		// TODO Auto-generated method stub
		return 0;
	}
}
class BorderNodes{
	Vector<SimpleTriangle>faces;
	Vector<Node>nodes;
	Vector<Node>nodesLeft=new Vector<Node>();
	Vector<Node>nodesRight=new Vector<Node>();
	Vector<Node>nodesTop=new Vector<Node>();
	Vector<Node>nodesBottom=new Vector<Node>();
	Bounds3D bounds=new Bounds3D();
	public void loadObj(String pathObjIn){
		bounds=new Bounds3D();
		nodes=new Vector<Node>();
		faces=new Vector<SimpleTriangle>();
		SimpleObjLoaderStream stream = new SimpleObjLoaderStream();
		stream.init(pathObjIn);
		float[] vertex = stream.readVertex();
		while (vertex != null) {
			nodes.add(new Node(vertex[0], vertex[1], vertex[2]));
			vertex = stream.readVertex();
		}
		//println("nodes: " + nodes.size());
		stream.close();
		stream.init(pathObjIn);
		int[] face = stream.readFace();
		while (face != null) {
			SimpleTriangle f = new SimpleTriangle(new Vec3D(),new Vec3D(),new Vec3D());
			if (face.length == 4) {
				f = new SimpleTriangle(nodes.get(face[0] - 1),
						nodes.get(face[1] - 1), nodes.get(face[2] - 1));
				faces.add(f);
				f = new SimpleTriangle(nodes.get(face[2] - 1),
						nodes.get(face[3] - 1), nodes.get(face[0] - 1));
				faces.add(f);

				for (int i = 0; i < face.length; i++) {
					Node n = nodes.get(face[i] - 1);
					n.setComment(1);
				}
			} else {
				f = new SimpleTriangle(nodes.get(face[0] - 1),
						nodes.get(face[1] - 1), nodes.get(face[2] - 1));
				for (int i = 0; i < face.length; i++) {
					Node n = nodes.get(face[i] - 1);
					n.setComment(1);
				}
				faces.add(f);
			}
			face = stream.readFace();
		}
	
		setPosition();
	}
	public void setPosition(){
		bounds=new Bounds3D();
		bounds.addAll(nodes);
		float xF=2f/bounds.getDimX();
		float yF=4f/bounds.getDimY();
		float zF=4f/bounds.getDimZ();
		
		
		float x2=bounds.getX2();
		float y1=bounds.getY2();
		float z=bounds.getCenterZ();
		for (int i=0;i<nodes.size();i++){
			Node n=nodes.get(i);
			n.setX(n.getX()-x2);
			n.setY(n.getY()-y1);
			n.setZ(n.getZ()-z);
			n.setX(n.getX()*xF);
			n.setY(n.getY()*yF);
			n.setZ(n.getZ()*zF);
		}
		bounds=new Bounds3D();
		bounds.addAll(nodes);
	}
	public void invertFaces(){
		for (int i=0;i<faces.size();i++){
			SimpleTriangle sT=faces.get(i);
			sT.invert();
		}
	}
	public void display(){
		fill(255);
		noStroke();
		for (int i=0;i<faces.size();i+=50){
			SimpleTriangle st=faces.get(i);
			st.display3D(g);
		}
		stroke(255,0,0);
		println(nodesLeft.size());
		for (int i=0;i<nodesLeft.size();i++){
			Node st=nodesLeft.get(i);
			point(st.x,st.y,st.z);
		}
		println(nodesRight.size());
		for (int i=0;i<nodesRight.size();i++){
			Node st=nodesRight.get(i);
			point(st.x,st.y,st.z);
		}
		
		stroke(0,255,0);
		for (int i=0;i<nodesTop.size();i++){
			Node st=nodesTop.get(i);
			point(st.x,st.y,st.z);
		}
		for (int i=0;i<nodesBottom.size();i++){
			Node st=nodesBottom.get(i);
			point(st.x,st.y,st.z);
		}
	}
	public void mirrorX(){
		for (int i=0;i<nodes.size();i++){
			Node n=nodes.get(i);
			n.setX(n.getX()*-1);
			n.setX(n.getX()+0.01f);
		}
		bounds=new Bounds3D();
		bounds.addAll(nodes);
	}
	
	public void filterUnusedNodes(){
		for (int i = 0; i < nodes.size(); i++) {
			Node n = nodes.get(i);
			n.setComment(0);
		}
		for (int i = 0; i < faces.size(); i++) {
			SimpleTriangle f = faces.get(i);
			for (int j = 0; j < f.getNodesNum(); j++) {
				Node n = (Node) f.getNode(j);
				n.setComment(1);
			}
		}
		Vector<Node>newNodes=new Vector<Node>();
		for (int i = 0; i < nodes.size(); i++) {
			Node n = nodes.get(i);
			if (n.getComment()==1){
				n.setComment(0);
				newNodes.add(n);
			}
		}
		nodes=newNodes;
		bounds=new Bounds3D();
		bounds.addAll(nodes);
		setPosition();
	}
	
	public void deleteBackFaces(float d){
		
		Vector<SimpleTriangle> newFaces=new Vector<SimpleTriangle>();
		for (int i=0;i<faces.size();i++){
			SimpleTriangle s=faces.get(i);
			boolean isborder=true;
			for (int j=0;j<s.getNodesNum();j++){
				HasPos3D n=s.getNode(j);
				if (n.getX()<bounds.getX2()-d){
					isborder=false;
					break;
				}
			}
			if (!isborder){
				newFaces.add(s);
			}
			else{
				cutFaces.add(s);
			}
		}
		faces= newFaces;
		filterUnusedNodes();
	}
	public void collectBorders(){
		nodesLeft=new Vector<Node>();
		nodesRight=new Vector<Node>();
		nodesTop=new Vector<Node>();
		nodesBottom=new Vector<Node>();
		float off=+0.007f;
		for (int i=0;i<nodes.size();i++){
			Node n=nodes.get(i);
			if (n.getX()==bounds.getX2()){
				
				if (n.getZ()<=bounds.getZ1()+off){
					nodesLeft.add(n);
				}
				if (n.getZ()>=bounds.getZ2()-off){
					nodesRight.add(n);
				}
				if (n.getY()<=bounds.getY1()+off){
					nodesBottom.add(n);
				}
				if (n.getY()>=bounds.getY2()-off){
					nodesTop.add(n);
				}
			
				
			}
			
		}
		NodeComparator nc=new NodeComparator(2);
		Collections.sort(nodesTop, nc);
		Collections.sort(nodesBottom, nc);
		nc=new NodeComparator(1);
		Collections.sort(nodesLeft, nc);
		Collections.sort(nodesRight, nc);
	}
	public void saveObjPrintwriter(String file) {
		PrintWriter output = createWriter(file + ".obj");

		int idV = 1;
		
		for (int i = 0; i < faces.size(); i++) {
			SimpleTriangle f = faces.get(i);
			for (int j = 0; j < f.getNodesNum(); j++) {
				Vec3D n = (Vec3D) f.getNode(j);
				
				if (n.getId() == 0) {
					n.setId(idV);
					idV++;
					output.println("v " + n.x + " " + n.y + " " + n.z);
				}
			}
		}
		
		
		for (int i = 0; i < faces.size(); i++) {
			SimpleTriangle f = faces.get(i);
			int[] ids = new int[f.getNodesNum()];
			String string = "f";
			
			for (int j = 0; j < f.getNodesNum(); j++) {
				Vec3D n = (Vec3D) f.getNode(j);
				string += " " + n.getId();
			}
			output.println(string);
		}
		
		output.flush(); // Writes the remaining data to the file
		output.close();
	}
	}

}


